package middleware

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

//Auth middleware
func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		claims, err := TokenValid(c)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"status":  http.StatusUnauthorized,
				"message": err.Error(),
			})
			c.Abort()
			return
		}
		c.Set("claims", claims)
		c.Next()
	}
}

//ExtractToken extract token from header
func ExtractToken(r *http.Request) string {
	bearToken := r.Header.Get("Authorization")
	strArr := strings.Split(bearToken, " ")
	if len(strArr) == 2 {
		return strArr[1]
	}
	return ""
}

//TokenValid verify token
func TokenValid(c *gin.Context) (jwt.Claims, error) {
	token, err := VerifyToken(c.Request)
	if err != nil {
		return nil, err
	}
	var (
		claims jwt.Claims
		ok     bool
	)
	if claims, ok = token.Claims.(jwt.Claims); !ok && !token.Valid {
		return nil, err
	}
	return claims, nil
}

//VerifyToken verify jwt
func VerifyToken(r *http.Request) (*jwt.Token, error) {
	tokenString := ExtractToken(r)
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		//Make sure that the token method conform to "SigningMethodHMAC"
		if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		key, err := jwt.ParseRSAPublicKeyFromPEM([]byte(
			`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2zyXE0t2dinn1eFuKfZx
qpbWAd8+ldaJPavFerUiwhkjOS10uQ54WpeFt7VE8ds5317qYkIqoNfRLmcMfXCc
J8RflBxTe/O9dUSiJPEOo2NmPWI2q7mc1ay6eT3JGrwn7ArClg4cg81QD+4Kh08h
HbVyDKztn41XwLtUAkx4nI/2T8Tj9WVnOCp4IDXAwuTd+EbTjI05QFpBw0NdIFs/
it2l5MtG74jSPk2gsSK4meJTSA/CSMz2o6xYw+63KGwQEy+vqgS/ER8tdP/alM5I
pbyES5WDAjJv1pTCNNN5LO+pthW123tz8Po7AHoMqVOU9wk1lbp1r7xDl49P735a
KwIDAQAB
-----END PUBLIC KEY-----
`))
		if err != nil {
			return nil, fmt.Errorf("err: %v", err)
		}

		return key, nil
	})
	if err != nil {
		return nil, err
	}
	return token, nil
}
